#pragma once
#include"basic_buf.hpp"
#include <vector>
#include <algorithm>


// 缓冲区本身需要维护线程安全
/*
    双缓冲：解决阻塞队列，频繁申请，释放锁，进一步提高效率
    
*/

// 是否扩容，安全模式 不进行扩容，非安全模式
enum class DOUBLE_BUF_TYPE
{
    SAFA,
    UNSAFA
};
#define DEFAULT_SZ 10
#define INCREASE_SZ 5   // 线程增长  > 阈值 线性变化
#define THRESHOLD_SZ 30 // 阈值  < 阈值 两倍变化

template<typename T>
class Buf
{
public:
    Buf(DOUBLE_BUF_TYPE type = DOUBLE_BUF_TYPE::SAFA)
    :_con_index(0)
    ,_pro_index(0)
    ,_type(type)
    {
        _buf.resize(DEFAULT_SZ);
    }
    int readable()
    {
        // 0 0 0 0 0 
        //   1     4
        return _pro_index - _con_index;
    }
    int writeable()
    {
        // 0 0 0 0 0 5
        //   1       4
        //  (end - begin]
        return _buf.size()  - _pro_index;
    }
    void addSpace(size_t sz)
    {
        int new_sz = _buf.size() > THRESHOLD_SZ ? _buf.size() + INCREASE_SZ + sz : \
                                _buf.size() * 2 + sz;
        _buf.resize(new_sz);
    }
    
    // 默认是sz是1，处理非字符串，非数组的形式
    // 如果你想传入字符串，数组也是可以
    void push(const T* data, size_t sz = 1)
    {
        if(writeable() < sz && _type == DOUBLE_BUF_TYPE::UNSAFA)
            addSpace(sz);
        if(sz > writeable() && _type == DOUBLE_BUF_TYPE::SAFA)
            sz = writeable();
        std::copy(data,data + sz, &_buf[_pro_index]);
        _pro_index += sz;
    }
    void pop(T* data,size_t sz = 1)
    {
        // 这么写，存在隐患，未来如果data给的空间不够大是会出错的
        // 所以外面的接口，一定要设置sz，保证调用时传入sz
        // 如果读完了，下标要重置
        int tmp = _con_index;
        // if(sz > readable())
        // {
        //     cout << "reset" << endl;
        //     sz = readable();
        //     reset();
        // }
        // 当消费者下标+sz 大于_buf时说明已经写满了，需要重置下标
        int flag = true;
        if(_con_index + sz >= _buf.size())
        {
            reset();
            flag = false;
        }
        std::copy(&_buf[tmp],&_buf[tmp] + sz,data);
        if(flag)
            _con_index += sz;

 
    }


    void swap(Buf<T>& buf)
    {
        _buf.swap(buf._buf);
        std::swap(buf._con_index,_con_index);
        std::swap(buf._pro_index,_pro_index);
    }
    void reset()
    {
        _con_index = _pro_index = 0;
    }
    bool isEmpty()
    {
        return _con_index == _pro_index;
    }
    bool isFull()
    {
        return _pro_index == _buf.size();
    }

public:
    std::vector<T> _buf;
    size_t _con_index;
    size_t _pro_index;
    DOUBLE_BUF_TYPE _type;
};


template<typename T>
class DoubleBuf: public basic_buf<T>
{
public:
    using basic_buf<T>:: _mutex_pro_con;
    using basic_buf<T>:: _cond_con; 
    using basic_buf<T>:: _cond_pro; 
    using ptr = std::shared_ptr<DoubleBuf>;
    DoubleBuf(DOUBLE_BUF_TYPE type = DOUBLE_BUF_TYPE::SAFA)
    :_con_buf(type)
    ,_pro_buf(type)
    ,_type(type)
    {}

    int writeable()
    {
        return _pro_buf.writeable();
    }

    // 生产和消费都站在生产缓冲区去看
    // 不然会很矛盾

    // 为双缓冲区设计的接口
    // 每次读取都读取完所有的
    virtual void pop(T* val)
    {
        pop(val,1);
    }
    virtual void push(const T& val)
    {
        push(val,1);
    }
    virtual void push(const T& val,size_t sz)
    {
        sleep(1);
        pthread_mutex_lock(&_mutex_pro_con);
        // 当生产缓冲区满了，阻塞等待
        while(_pro_buf.isFull())
        {
            // cout << "我是生产者，我被阻塞了" << endl;
            pthread_cond_wait(&_cond_pro,&_mutex_pro_con);
        }
        // cout << "我是生产者，我被唤醒了" << endl;

        _pro_buf.push(&val,sz);
        pthread_cond_broadcast(&_cond_con);
        pthread_mutex_unlock(&_mutex_pro_con);

        //debug
        // cout << "pro" << endl;
        // cout << "_con_buf: " << endl;
        // cout << "_con_index = " << _con_buf._con_index << "_pro_index = " << _con_buf._pro_index << endl;
        // cout << "_pro_buf: " << endl;
        // cout << "_con_index = " << _pro_buf._con_index << "_pro_index = " << _pro_buf._pro_index << endl;
        // cout << "-------------------" << endl;

        // 唤醒消费者的原因是，生产缓冲区中有数据了
        // 所以消费者也要因为这个原因而阻塞，
        // 所以说要站在生产缓冲区的角度
        

    }
    virtual void pop(T* val,size_t sz) 
    {
    //     cout << "-------------------" << endl;
    //     cout << "con swap before" << endl;
    //     cout << "_con_buf: " << endl;
    //     cout << "_con_index = " << _con_buf._con_index << " _pro_index = " << _con_buf._pro_index << endl;
    //     cout << "_pro_buf: " << endl;
    //     cout << "_con_index = " << _pro_buf._con_index << " _pro_index = " << _pro_buf._pro_index << endl;
    //     cout << "-------------------" << endl;
        // 还有一个加锁的原因，要控制生产则和消费者的同步关系得加锁
        pthread_mutex_lock(&_mutex_pro_con);
        // 如果生产者缓冲区中没有数据则进行阻塞
        while(_pro_buf.isEmpty())
        {
            // cout << "我是消费者，我被阻塞住了" << endl;
            pthread_cond_wait(&_cond_con,&_mutex_pro_con);
        }
        // cout << "我是消费者，我被唤醒了" << endl;
        
        // 被唤醒说明生产者缓冲区有数据，消费者缓冲区是否有数据，我消费者不关心
        // 消费者交换，换到有数据的再说
        //debug


        _con_buf.swap(_pro_buf);
        // cout << "con swap  after" << endl;
        // cout << "_con_buf: " << endl;
        // cout << "_con_index = " << _con_buf._con_index << " _pro_index = " << _con_buf._pro_index << endl;
        // cout << "_pro_buf: " << endl;
        // cout << "_con_index = " << _pro_buf._con_index << " _pro_index = " << _pro_buf._pro_index << endl;
        // cout << "-------------------" << endl;
        _con_buf.pop(val,sz);
        pthread_cond_broadcast(&_cond_pro);
        pthread_mutex_unlock(&_mutex_pro_con);

        // cout << "con swap  pop after" << endl;
        // cout << "_con_buf: " << endl;
        // cout << "_con_index = " << _con_buf._con_index << " _pro_index = " << _con_buf._pro_index << endl;
        // cout << "_pro_buf: " << endl; 
        // cout << "_con_index = " << _pro_buf._con_index << " _pro_index = " << _pro_buf._pro_index << endl;
        // cout << "-------------------" << endl;
        // sleep(1);


    }
    virtual bool empty()
    {
        return _con_buf.isEmpty() && _pro_buf.isEmpty();
    }

    virtual bool full()
    {
        return _con_buf.isFull() && _pro_buf.isFull();
    }


private:
    Buf<T> _con_buf;
    Buf<T> _pro_buf;
    DOUBLE_BUF_TYPE _type;

};

